﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
using System.Runtime.Serialization;
using System.Collections;
using System.Xml.Serialization;
using System.ComponentModel;
using System.Collections.Specialized;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using BrainTechLLC.ThreadSafeObjects;

namespace BrainTechLLC
{
    [Serializable]
    [DataContract]
#if NO_SILVERLIGHT
    [Browsable(true)]
    [TypeConverter(typeof(ExpandableObjectConverter))]
    [EditorBrowsable(EditorBrowsableState.Always)]
#endif
    public class StateCollection : AssociatedIDCollection
    {
        [DataMember]
        public long _associatedWith;

        [NonSerialized, XmlIgnore]
        public bool _dirty;

        [NonSerialized, XmlIgnore]
        public ThreadSafeLookup<string, State> _cachedStatesByName;
        
#if NO_SILVERLIGHT
        [EditorBrowsable(EditorBrowsableState.Always)]
#endif
        [XmlIgnore]
        public long AssociatedWith
        {
            get { return _associatedWith; }
            set { _associatedWith = value; }
        }

        public void RemoveState(long stateID)
        {
            Remove(stateID);
            _dirty = true;
            LinkUpStates();
        }

        public void RemoveState(string stateName)
        {
            State s = FindStateByName(stateName);
            
            if (s != null)
                RemoveState(s.AssociatedID);
        }

        public void AddState(State state, int scheduleMS)
        {
            state.Register();
            state.AutoScheduleMS = scheduleMS;
            state.ParentStateCollection = this;
            Add(state.AssociatedID);
            _dirty = true;
            LinkUpStates();
        }

        public void LinkUpStates()
        {
            var states = StatesByName.ToList();
            for (int n = 0; n < states.Count; n++)
            {
                State state = states[n].Value;
                state.ParentStateCollection = this;

                if (state._modifications != null)
                    state._modifications.Clear();
            }
            for (int n = 0; n < states.Count; n++)
            {
                State state = states[n].Value;
                if (state._modifyExecutingState != null)
                {
                    foreach (var kvp in state.ModifyExecutingState)
                    {
                        State found = FindStateByName(kvp.Key);
                        if (found != null)
                        {
                            found.Modifications.Add(state);
                        }
                    }
                }
                if (!state._scheduled && state.AutoScheduleMS > 0)
                {
                    state._scheduled = true;
                    Globals.SchedulingEngine.ScheduleEventToExecute(state, state.AutoScheduleMS);
                }
            }
        }

#if NO_SILVERLIGHT
        [EditorBrowsable(EditorBrowsableState.Always)]
#endif
        [XmlIgnore]
        public ThreadSafeLookup<string, State> StatesByName
        {
            get
            {
                if (_cachedStatesByName == null || _dirty)
                {
                    _dirty = false;
                    bool allStatesLoaded = true;
                    ThreadSafeLookup<string, State> results = new ThreadSafeLookup<string, State>(StringComparer.OrdinalIgnoreCase);
                    List<IGameThing> things = Everything.Find<IGameThing>(this.AllItems);
                    for (int n = 0; n < things.Count; n++)
                    {
                        State thing = things[n] as State;
                        if (thing == null)
                        {
                            allStatesLoaded = false;
                            break;
                        }

                        if (thing != null)
                        {
                            if (!results.ContainsKey(thing.StateName))
                                results.Add(thing.StateName, thing);
                        }
                    }
                    if (!allStatesLoaded)
                    {
                        return new ThreadSafeLookup<string, State>(StringComparer.OrdinalIgnoreCase);
                    }
                    else
                    {
                        _cachedStatesByName = results;
                    }
                }

                return _cachedStatesByName;
            }
        }

        public State FindStateByName(string name)
        {
            State state = null;
            StatesByName.TryGetValue(name, out state);
            return state;
        }
    }
}
